#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <avr/wdt.h>
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <util/delay.h>

#include "AvrStd/TWI.h"

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

#define WRITE 0
#define READ 1

char buffer[6];
uint8_t stage = 0;
unsigned char temp = 0;
uint8_t val = 0;
uint8_t adr = 0;
uint8_t status = 0x00; // mode defined | r/w | read_adr_defined | write_adr_defined | write_val_defined | switch | |
uint8_t ctr = 0;
char data = 0;

#define MODE_DEFINED      0b00000001
#define R_W               0b00000010
#define Read_Adr_Defined  0b00000100
#define Write_Adr_Defined 0b00001000
#define Write_Val_Defined 0b00010000
#define Switch            0b00100000

void Putc(unsigned char c)
{
    while (!(UCSRA & (1<<UDRE)))
    {
    }
    UDR = c;                      /* sende Zeichen */
}

void Puts (char *s)
{
    while (*s)// while current pointer isn't pointing to '/0' wich is the 'String-end-sign'
    {
        Putc(*s);
        s++;
    }
}

uint8_t WriteRom(uint8_t adr,uint8_t value) //too lazy to write EEPROM every time... THROOOUGH THE FIIIIRE AND FLAAAAMES DLDLDLDLDLDLDLDLDLDDLLDDDLDDDDLDDD D D D  DD  D D
{
    uint8_t toReturn = 0;
    twi_start();
    if (twi_SendAddress_ack(0xA0, 1))
    {

        twi_write(adr);
        twi_write(value);
        toReturn = 1;
    }
    else
    {
        toReturn = 0;
    }
    twi_stop();
    return toReturn;
}

void WriteRomUnSafe(uint8_t adr,uint8_t value)
{
    uint8_t toReturn = 0;
    twi_start();
    twi_SendAddress(0xA0, WRITE);

    twi_write(adr);
    twi_write(value);

    twi_stop();
}

uint8_t ReadRom(uint8_t adr)
{
    uint8_t toReturn =0;
    twi_start();
    twi_SendAddress(0xA0, WRITE);
    twi_write(adr);
    twi_repStart();
    twi_SendAddress(0xA0, READ);
    twi_nack();
    toReturn = twi_recv();
    twi_stop();
    return toReturn;
}

int main (void)
{
    UCSRB |= (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
    UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes
    UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
    UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
    UCSRB |= (1 << RXCIE);
    twi_init();
    /*    char data = 0;
        //eeprom (Microchip 24LC01B) has address 0xA0
        //Puts("Init");
        twi_start();
        twi_SendAddress(0xA0, WRITE);
        twi_write(0x01); //write to second WORD
        twi_write(0x7B);//DEC=123 HEX=7B BIN=0111 1011
        twi_stop();

        //Puts("Stop sent, Delay 100ms");
        _delay_ms(100);

        twi_start();
        twi_SendAddress(0xA0, WRITE);
        twi_write(0x01);
        twi_repStart();
        twi_SendAddress(0xA0, READ);
    	twi_nack();
        data = twi_recv();
        twi_stop();
        //Puts("Data:\r\n");

        Putc(data);*/

    sei();  //enable interrupts globally
    while ( 1 )
    {

    }

}

void clearArray(void)
{
    uint8_t i;
    for (i= 0; i <= sizeof(buffer); i++)
    {
        buffer[i] = 0;
    }
    ctr = 0;
}

void clear (void)
{
    adr = 0;
    val = 0;
    status = 0x00;
    ctr = 0;
    data = 0;
    clearArray();
}

ISR(USART_RXC_vect)
{
    cli();//disable interrupts

    char Received;
    Received = UDR; // Fetch the recieved byte value into the variable "ByteReceived"
    //UDR = ReceivedByte; // Echo back the received byte back to the computer
    //Putc('A');
    /*	if(Received <= 90 && Received >= 65) //ABC...Z
    	{
    		Received += 32; //Makes an Lowercase char (ASCII) out of an Uppercase char! Easy :)
    	}*/
    temp = Received;
    Putc(Received);
    //\r\n
    //r (read) | (space) | value | CRLF
    //w (write) | (space) | addr | (space) | value | CRLF
    //    	0       1        2       3         4       5
    if (!(status & MODE_DEFINED)) //if Mode undefined
    {
        if (temp == 'r')
        {
            status &= ~R_W; //clear r/w bit
            status |= MODE_DEFINED; //set mode_defned
            // Puts("Mode R");

        }
        else if (temp == 'w')
        {
            status |= R_W; //set r/w bit
            status |= MODE_DEFINED; //set mode_defined
            //Puts("Mode W");
        }
        else
        {
            Puts("Error Interpreting your Request :(\r\n");
        }
    }
    else
    {
        //read
        if (!(status & R_W)) //if r/w bit is clear
        {
            if (!(status & Read_Adr_Defined))//if read adr un-defined
            {
                if (temp == '\r')
                {
                    adr = atoi(buffer);
                    clearArray(); //clear array for new data
                    status |= Read_Adr_Defined; //set Read_Adr_Defined
                    //Putc('1');
                    //Putc(adr);
                    // Puts("gonna read!\r\n");

                    data = ReadRom(adr);
                    Putc(data);

                    clear();
                }
                else if (temp == ' ')
                {
                    // Putc('2');
                }
                else
                {
                    // Putc('3');
                    buffer[ctr] = (temp);
                    ctr++;
                }
            }
        }

        //write
        else if (status & R_W)//if r/w bit is set
        {
            if ((temp ==' ') && (!(status & Switch)))
            {
                status |= Switch;
                //  Putc('a');
            }
            else if ((!(status & Write_Adr_Defined)) && (status & Switch))//if write adr un-defined
            {
                if (temp == ' ')//space should equal 0x20
                {
                    adr = atoi(buffer);
                    clearArray();
                    status |= Write_Adr_Defined; //set Write_Adr_Defined
                    // Putc('1');
                    // Putc(adr);
                }
                else
                {
                    buffer[ctr] = (temp);
                    ctr++;
                }
            }
            else if (!(status & Write_Val_Defined))//if write val un-defined
            {
                if (temp == '\r' || temp == '\n')
                {
                    val = atoi(buffer);
                    clearArray();
                    status |= Write_Val_Defined;
                    //Putc('2');
                    //Putc(val);
                }
                else
                {
                    buffer[ctr] = (temp);
                    ctr++;
                }
            }
            if ((status & Write_Adr_Defined) && (status & Write_Val_Defined))
            {
                // Puts("gonna write\r\n");
               // Putc(adr);
               // Putc(val);
                uint8_t ret = WriteRom(adr, val);
                Putc(ret);
                clear();
            }
        }

        else
        {
            Puts("Error handling your Request ");
            clear();
            Puts("Cleared\r\n");
        }
    }
    sei(); //enable interrupts again
}
